/* ->c.wos */

/* Ovation!   (c) D. J. Pilling,  December 1988                     */
/*                       Wimp/OS routines                             */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>

#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.werr"
#include "h.wimpt"
#include "h.bbc"
#include "h.akbd"
#include "h.kernel"
#include "h.swis"
#include "h.font"

#include "h.swinos"
#include "h.wos"
#include "h.main"
#include "h.timex"
#include "h.view"

#include "h.mym"
#include "h.trans"

#include "h.ram"
#include "h.key"






/***************************************************************************/

wimp_eventstr wimpevent,wimpfirst;
int           icon;
int           ewindow;
int           buttons;
int           mousex,mousey,mhandle,micon;
int           x0,x1,y0,y1,bx,by,bhandle,scx,scy,wflags;
int           ix0,ix1,iy0,iy1;
int           chandle,cicon;
int           ox0,ox1,oy0,oy1;


int draghandle;
int dragtype;

int timeout;


int wimp_version;


/****************************************************************************/

int deltax;
int deltay;
int maskx;
int masky;
int screenx;
int screeny;
int lndeltax;
int lndeltay;
int ncolours;
int gcharsizex;
int gcharsizey;
int gcharspacex;
int gcharspacey;
int ln2bpp;

wimp_palettestr vdupal;
int             wimpcolnos[16];

int hscrlbar=40;
int vscrlbar=40;



/*

void getdeltas(int mode,int * dx,int * dy)
{
 int xospx,yospx;
 xospx=(1 << bbc_modevar(mode,bbc_XEigFactor));
 yospx=(1 << bbc_modevar(mode,bbc_YEigFactor));
 *dx=xospx;
 *dy=yospx;
}


void getcurdeltas(int * dx,int * dy)
{
 int lndeltax=bbc_vduvar(bbc_XEigFactor);
 int lndeltay=bbc_vduvar(bbc_YEigFactor);
 *dx=(1 << lndeltax);
 *dy=(1 << lndeltay);
}

 */




void vdupalvars(void)
{
 int i;

 wimp_readpalette(&vdupal);

 for(i=0;i<16;i++) wimpcolnos[i]=getcolnumber(vdupal.c[i].word);
}



void vdumodevars(void)
{
 int xpic,ypic;

 xpic=bbc_vduvar(bbc_XWindLimit);
 ypic=bbc_vduvar(bbc_YWindLimit);

 lndeltax=bbc_vduvar(bbc_XEigFactor);
 lndeltay=bbc_vduvar(bbc_YEigFactor);
 deltax=(1 << lndeltax);
 deltay=(1 << lndeltay);

 maskx=0xFFFFFFFF-(deltax-1);
 masky=0xFFFFFFFF-(deltay-1);

 screenx=(xpic+1)*deltax;
 screeny=(ypic+1)*deltay;

 ncolours=bbc_vduvar(bbc_NColour);

 gcharsizex=bbc_vduvar(bbc_GCharSizeX);
 gcharsizey=bbc_vduvar(bbc_GCharSizeY);
 gcharspacex=bbc_vduvar(bbc_GCharSpaceX);
 gcharspacey=bbc_vduvar(bbc_GCharSpaceY);
 ln2bpp=bbc_vduvar(bbc_Log2BPP); 

 vdupalvars();
}



int osver(void)
{
 os_regset rx;

 rx.r[0]=129;
 rx.r[1]=0;
 rx.r[2]=0xFF;

 os_swix(OS_Byte,&rx);

 return(rx.r[1]);
}


int os3;
int os35;


void setosversions(void)
{
 int os;

 os=osver();

 os3=os>=0xA4;
 os35=os>=0xA5;
}


void seti(handle,icon,eor,bic) int handle,icon,eor,bic;
{
 wimp_set_icon_state(handle,icon,eor,bic);
}


void select(handle,icon) int handle,icon;
{
 seti(handle,icon,0x200000,0x200000);
}


void deselect(handle,icon) int handle,icon;
{
 seti(handle,icon,0,0x200000);
}


void selectst(int handle,int icon,int state)
{
 if(state) select(handle,icon);
 else      deselect(handle,icon);
}




void shadeicon(int window,int icon)
{
 seti(window,icon,0x400000,0x400000);
}


void unshadeicon(int window,int icon)
{
 seti(window,icon,0x000000,0x400000);
}



void shadeicon2(int window,int icon)
{
 seti(window,icon,0x3000000,0xF000000);
}


void unshadeicon2(int window,int icon)
{
 seti(window,icon,0x7000000,0xF000000);
}


/*

void makemenuicon(int window,int icon)
{
 seti(window,icon,0x9000,0xF000);
}


void unmakemenuicon(int window,int icon)
{
 seti(window,icon,0x0,0xF000);
}


void makemenust(int window,int icon,int state)
{
 if(state) makemenuicon(window,icon);
 else      unmakemenuicon(window,icon); 
}

 */


void shadeiconst(int window,int icon,int state)
{
 if(state) shadeicon(window,icon);
 else      unshadeicon(window,icon);
}

void shadeiconst2(int window,int icon,int state)
{
 if(state) shadeicon2(window,icon); 
 else      unshadeicon2(window,icon);
}


/*

void writeableicon(int window,int icon)
{
 seti(window,icon,0xF000,0xF000);
}

void unwriteableicon(int window,int icon)
{
 seti(window,icon,0x6000,0xF000);
}

*/


void getpointer(void)
{
 wimp_mousestr mstr;
 wimp_get_point_info(&mstr);
 mousex=mstr.x;
 mousey=mstr.y;
 buttons=mstr.bbits;
 mhandle=mstr.w;
 micon  =mstr.i;
}


void getw(handle) int handle;
{
 wimp_wstate winds;
 wimp_get_wind_state(handle,&winds);
 x0=winds.o.box.x0;
 y0=winds.o.box.y0;
 x1=winds.o.box.x1;
 y1=winds.o.box.y1;
 scx=winds.o.x;
 scy=winds.o.y;
 bhandle=winds.o.behind;
 wflags=winds.flags;
 bx=x0-scx;
 by=y1-scy;
}

void geti(handle,icon) int handle,icon;
{
 wimp_icon istate;
 wimp_get_icon_info(handle,icon,&istate);
 ix0=istate.box.x0;
 iy0=istate.box.y0;
 ix1=istate.box.x1;
 iy1=istate.box.y1; 
}




void dragicon(int mx,int my,int w,int i)
{
 wimp_dragstr drg;

 draghandle=w;
 getw(w);
 geti(w,i);

 drg.window=w;
 drg.type=5;
 drg.box.x0=bx+ix0;
 drg.box.y0=by+iy0;
 drg.box.x1=bx+ix1;
 drg.box.y1=by+iy1;
 drg.parent.x0=drg.box.x0-mx;
 drg.parent.y0=drg.box.y0-my;
 drg.parent.x1=drg.box.x1-mx+screenx;
 drg.parent.y1=drg.box.y1-my+screeny;

 wimp_drag_box(&drg);
}


/*****************************************************************************/

static int dragaspritestarted;

void dragasprite(int w,int i)
{
 os_regset rx;
 int       coords[4];

 if(os3)
 {
  rx.r[0]=161;
  rx.r[1]=28;
  os_swix(OS_Byte,&rx);
  if(rx.r[2] & 0x2)
  {
   getw(w);
   geti(w,i);

   coords[0]=bx+ix0;
   coords[1]=by+iy0;
   coords[2]=bx+ix1;
   coords[3]=by+iy1;

   rx.r[0]=(01)+((01)<<2)+((00)<<4)+((1)<<6)+((1)<<7);
   rx.r[1]=1;
   rx.r[2]=(int)iconaddr(w,i);
   rx.r[3]=(int)coords;

   dragaspritestarted=(os_swix(DragASprite_Start,&rx)==NULL);
  }
 }
}

void dragaspritestop(void)
{
 os_regset rx;
 if(dragaspritestarted) os_swix(DragASprite_Stop,&rx);
}

/*****************************************************************************/


void open(int handle,int x0,int y0,int x1,int y1,int scx,int scy,int behind)
{
 wimp_openstr oblock;
 oblock.w=handle;
 oblock.box.x0=x0;
 oblock.box.x1=x1;
 oblock.box.y0=y0;
 oblock.box.y1=y1;
 oblock.x=scx;
 oblock.y=scy;
 oblock.behind=behind;
 wimp_open_wind(&oblock);
}

void extent(int handle,int x0,int y0,int x1,int y1)
{
  wimp_redrawstr eblock;
  eblock.w=handle;
  eblock.box.x0=x0;
  eblock.box.y0=y0;
  eblock.box.x1=x1;
  eblock.box.y1=y1;
  wimp_set_extent(&eblock);
}


char * iconaddr(handle,icon) int handle,icon;
{ 
 static wimp_icon istate;
 wimp_get_icon_info(handle,icon,&istate);

 if(istate.flags & 0x100) return(istate.data.indirecttext.buffer);
 else return(istate.data.text);
}



void caret(int handle,int icon,int x,int y,int height,int index)
{
  wimp_caretstr cblock;
  cblock.w=handle;
  cblock.i=icon;
  cblock.x=x;
  cblock.y=y;
  cblock.height=height;
  cblock.index=index;
  wimp_set_caret_pos(&cblock);
}


void iecarrot(int wh,int ih)
{ 
 caret(wh,ih,0,0,-1,strlen(iconaddr(wh,ih)));
}



/*

void incarrot(int wh,int ih)
{
 char * c=iconaddr(wh,ih);
 while(1)
 {
  if((*c<'0' || *c>'9') && *c!='.' && *c!='/') break;
  c++;
 }
 caret(wh,ih,0,0,-1,c-iconaddr(wh,ih));
}
 */


void setfocus(int handle)
{
 caret(handle,-1,200,200,20,0);
}


void findcaret(void)
{ 
 wimp_caretstr cblock;
 wimp_get_caret_pos(&cblock);
 chandle=cblock.w;
 cicon=cblock.i;
}



char * xstrncpy(char *s1,char *s2,int n)
{

 while(n-->0)
   if((*s1++=*s2++)<32) break;
 *(s1-1)=0;

 return(s1);
}





void writeicon(int window,int icon,char * string)
{   int more;
    wimp_icon       isblock;
    wimp_icreate    iblock;
    wimp_redrawstr  rblock;
    wimp_caretstr   cblock;
    int             len;

    wimp_get_caret_pos(&cblock);

    wimp_get_icon_info(window,icon,&isblock);

    if(isblock.flags & 0x100)
    {
     xstrncpy(isblock.data.indirecttext.buffer,string,
              isblock.data.indirecttext.bufflen);
    }
    else
    {
     xstrncpy(isblock.data.text,string,12);
     wimp_delete_icon(window,icon);
     iblock.w=window;
     iblock.i=isblock;
     wimp_create_icon(&iblock,&icon);
    }

    rblock.w=window;
    rblock.box=isblock.box;
  
   wimp_update_wind(&rblock,&more);
   while(more)
   {
   wimp_get_rectangle(&rblock,&more);
   }
    
   if(cblock.i==icon && cblock.w==window)
   {
    len=strlen(string);
    cblock.index=len;
    wimp_set_caret_pos(&cblock);
   }
}


void writeiconf(int window,int icon,char * format, ...)
{
 va_list args;
 char v[128];
 va_start(args, format);
 vsprintf(v, format, args);
 writeicon(window,icon,v);
 va_end(args);
}



int geticonint(int handle,int icon,int * val)
{
 int code;
 code=sscanf(iconaddr(handle,icon),"%d",val);
 return(code==1);
}




void setspa(int window,int icon,int len,char * name)
{ 
 wimp_icon       isblock;
 wimp_icreate    iblock;

 wimp_get_icon_info(window,icon,&isblock);

 isblock.data.indirectsprite.spritearea=sprites;
 isblock.data.indirectsprite.name=name;
 isblock.data.indirectsprite.nameisname=len;

 isblock.flags|=wimp_INDIRECT;

 wimp_delete_icon(window,icon);
 iblock.w=window;
 iblock.i=isblock;
 wimp_create_icon(&iblock,&icon);
}




void setindirect(int window,int icon,int len,char * string)
{ 
 wimp_icon       isblock;
 wimp_icreate    iblock;

 wimp_get_icon_info(window,icon,&isblock);

 isblock.data.indirecttext.buffer=string;
/* isblock.data.indirecttext.validstring=NULL; */
 isblock.data.indirecttext.bufflen=len;

 isblock.flags|=wimp_INDIRECT;

 wimp_delete_icon(window,icon);
 iblock.w=window;
 iblock.i=isblock;
 wimp_create_icon(&iblock,&icon);
}





void radioon(int window,int icon)
{
 writeicon(window,icon,"radioon");
}


void radiooff(int window,int icon)
{
 writeicon(window,icon,"radiooff");
}


void radiost(int window,int icon,int state)
{
 if(state) radioon(window,icon);
 else      radiooff(window,icon);
}


void opton(int window,int icon)
{
 writeicon(window,icon,"opton");
}


void optoff(int window,int icon)
{
 writeicon(window,icon,"optoff");
}


void optst(int window,int icon,int state)
{
 if(state) opton(window,icon);
 else      optoff(window,icon);
}


void geto(int window)
{
wimp_redrawstr r;
r.w=window;
wimp_getwindowoutline(&r);
ox0=r.box.x0;
ox1=r.box.x1;
oy0=r.box.y0;
oy1=r.box.y1;
}



void setmouse(int x,int y)
{
  char blk[5];
  os_error * errpoi;

  blk[0]=3;
  blk[1]=x;blk[2]=x >> 8;
  blk[3]=y;blk[4]=y >> 8;

  errpoi=os_word(21,blk);
}



void refreshwindowtitle(int handle)
{
 wimp_redrawstr r;

 getw(handle);
 geto(handle);

 r.w=-1;
 r.box.x0=x0;
 r.box.x1=x1;
 r.box.y1=oy1;
 r.box.y0=y1;

 wimp_force_redraw(&r);
}


/* complete repaint of window contents */

void refreshwindow(int handle)
{
 wimp_redrawstr r;
 getw(handle);
 r.box.x0=x0-bx;
 r.box.x1=x1-bx;
 r.box.y0=y0-by;
 r.box.y1=y1-by;
 r.w=handle;
 wimp_force_redraw(&r);
}




os_error * oscli(char * string)
{
 return(os_cli(string));
}


void fx(int a,int x,int y)
{
 os_regset rx;

 rx.r[0]=a;
 rx.r[1]=x;
 rx.r[2]=y;

 os_swix(OS_Byte,&rx);
}



/*****************************************************************************/
                               /* Hourglass code */



/*

void hourglasspc(int percent)
{
  os_regset rx;
  rx.r[0]=percent;
  os_swix(Hourglass_Percentage,&rx);
}


void hourglasssmash(void)
{
  os_regset rx;
  os_swix(Hourglass_Smash,&rx);
}

 */

void hourglassoff(void)
{
  os_regset rx;
  os_swix(Hourglass_Off,&rx);
}


void hourglasson(void)
{
  os_regset rx;
  os_swix(Hourglass_On,&rx);
}

/*

void hourglassonafter(int delay)
{
  os_regset rx;
  rx.r[0]=delay;
  os_swix(Hourglass_Start,&rx);
}

 */


/****************************************************************************/


os_error * throwbackstart(void)
{
 os_error * ep;
 os_regset  rx;

 ep=os_swix(DDEUtils_ThrowbackStart,&rx);

 return(ep);
}


os_error * throwbackend(void)
{
 os_error * ep;
 os_regset  rx;

 ep=os_swix(DDEUtils_ThrowbackEnd,&rx);

 return(ep);
}



os_error * throwbacksend(int reason,...)
{
 os_error * ep;
 os_regset  rx;

 va_list args;

 va_start(args, reason);

 rx.r[0]=reason;

 switch(reason)
 {
  case   Throwback_ReasonProcessing:
                                    rx.r[2]=(int)(va_arg(args,int));
                                    break;

  case Throwback_ReasonErrorDetails:
                                    rx.r[2]=(int)(va_arg(args,int));
                                    rx.r[3]=va_arg(args,int);
                                    rx.r[4]=va_arg(args,int);
                                    rx.r[5]=(int)(va_arg(args,int));
                                    break;

  case  Throwback_ReasonInfoDetails:
                                    rx.r[2]=(int)(va_arg(args,int));
                                    rx.r[3]=va_arg(args,int);
                                    rx.r[4]=0;
                                    rx.r[5]=(int)(va_arg(args,int));
                                    break;
 }


 va_end(args);

 ep=os_swix(DDEUtils_ThrowbackSend,&rx);

 return(ep);
}


/*****************************************************************************/


void centerwindow(wimp_wstate * wst,int handle,int i)
{
  int width;
  int height;
  int left;
  int top;

  wimp_get_wind_state(handle,wst);

  width=wst->o.box.x1-wst->o.box.x0;
  height=wst->o.box.y1-wst->o.box.y0;

  left=(screenx-width)>>1;
  top=(screeny-height)>>1;

  left+=hscrlbar*(i % 4);
  top-=vscrlbar*(i % 5);

  wst->o.box.x0=left;
  wst->o.box.y0=top;
  wst->o.box.x1=wst->o.box.x0+width;
  wst->o.box.y1=wst->o.box.y0+height;

  wst->o.behind=-1;
}



void popup(int handle,int i)
{
 wimp_wstate wst;
 centerwindow(&wst,handle,i);
 wimp_open_wind(&wst.o);
}




void reopenw(int handle)
{
 wimp_wstate wst;
 wimp_get_wind_state(handle,&wst);
 wimp_open_wind(&wst.o);
}


/* moves a window forward to the front of stack */

void forward(int handle)
{
 wimp_wstate wblock;
 wimp_get_wind_state(handle,&wblock);
 wblock.o.behind=-1;
 wimp_open_wind(&wblock.o);
}


void openatscroll(int handle,int scx,int scy)
{
 wimp_wstate wblock;
 wimp_get_wind_state(handle,&wblock);
 wblock.o.x=scx;
 wblock.o.y=scy;
 wimp_open_wind(&wblock.o);
}


/* force window to lie inside screen border etc. */

void clipwindow(wimp_openstr * wopen,int andscroll)
{
 int maxwidth;
 int maxheight;
/* int vscrlbar;
 int hscrlbar;


 geto(wopen->w);
 getw(wopen->w);

 hscrlbar=oy1-y1;
 vscrlbar=ox1-x1;
*/

 if(wopen->box.x0<deltax) 
 {
  wopen->box.x1-=(wopen->box.x0-deltax);
  wopen->box.x0=deltax;
 }

 maxwidth=andscroll?screenx-vscrlbar:screenx;

 if((wopen->box.x1-wopen->box.x0)>=maxwidth)
 {
  wopen->box.x1=wopen->box.x0+maxwidth;
 }


 if(wopen->box.y1>(screeny-hscrlbar/* -deltay */))
 {
  wopen->box.y0-=wopen->box.y1-(screeny-hscrlbar/* -deltay*/);
  wopen->box.y1=screeny-hscrlbar/*-deltay*/;
 }

 maxheight=screeny-(3*hscrlbar)/2;

 if((wopen->box.y1-wopen->box.y0)>maxheight)
 {
  wopen->box.y0=wopen->box.y1-maxheight;
 }

}



void popupc(int tag)
{
 if(!createwindow(tag)) return;
 popup(whandle[tag],0);
}



/*  wimp_mousestr mstr;
  wimp_get_point_info(&mstr);
  wimp_create_menu((wimp_menustr *)window,mstr.x-80,mstr.y+80); */

 /* zapmenu(); */


/* pops up menu style window */

void menuwindow(int handle)
{
 wimp_wstate wst;

 centerwindow(&wst,handle,0);
 wimp_create_menu((wimp_menustr *)handle,wst.o.box.x0,wst.o.box.y1);
 repopf=0;
}


/****************************************************************************/

int conf_ok;
int doconfirm;
int conmode; /* CONYN Yes/No CONDN Discard/Cancel CONSDC Save/Discard/Cancel */


void conficon(void)
{
 switch(icon)
 {
  case 0:
  case 1:
         conf_ok=icon;
         break;

  case 4:
         conf_ok=-1;  /* Cancel */
         break;

  case 5:
         conf_ok=0;   /* Discard==No */
         break;

  case 3:
         if(conmode==CONDC) conf_ok=1;  /* Discard same as  YES */
                                        /* Are you sure you want to Quit? */
         else
         if(conmode==CONSDC) conf_ok=1; /* Save  */
         break;
 }
}


void confkey(int * key)
{
 int ch;

 ch=toupper(*key);

 if(*key==27)
 {
  conf_ok=-1;
 }
 else
 if(conmode==CONYN)
 {
  if(ch=='Y') conf_ok=1;
  else
  if(ch=='N') conf_ok=0;
  else        return;
 }
 else
 if(conmode==CONDC)
 {
  if(ch=='C') conf_ok=-1;
  else
  if(ch=='D') conf_ok=1;
  else        return;
 }
 else
 if(conmode==CONSDC)
 {
  if(ch=='S') conf_ok=1;
  else
  if(ch=='D') conf_ok=0;
  else
  if(ch=='C') conf_ok=-1;
  else        return;
 }
 else return;
 *key=-1;
}



/* returns 1==OK 0==NO -1==FORGET IT */


int confirm(int mode,char * format, ...)
{
 va_list args;
 char string[256];
 int handle;
 int i;

 va_start(args, format);
 vsprintf(string, format, args);
 va_end(args);
 trans(string,sizeof(string));

 if(!doconfirm)
 {
  if(mode==CONSDC) return(0);
  else             return(1);
 }


 if((handle=createwindow(CONF))==NULL) return(-1);

 conmode=mode;

 if(mode==CONYN)
 {
  wimp_delete_icon(handle,3);
  wimp_delete_icon(handle,4);
  wimp_delete_icon(handle,5);
 }
 else
 if(mode==CONDC)
 {
  writeicon(handle,3,transtoken("CN0"));  /* Discard */
  wimp_delete_icon(handle,0);
  wimp_delete_icon(handle,1);
  wimp_delete_icon(handle,5);
 }
 else
 if(mode==CONSDC)
 {
  writeicon(handle,3,transtoken("CN1"));   /* Save */
  wimp_delete_icon(handle,0);
  wimp_delete_icon(handle,1);
 }

 writeicon(handle,2,string);
 conf_ok=-2;

 menuwindow(handle);

 while(conf_ok==-2)
 {
  getw(handle);
  if(!(wflags & 0x10000))
  {
   conf_ok=-1;
   break;
  }
  poll(0);
 }

 while(1)
 {
  getpointer();
  poll(0);
  if(!buttons)
  {
   for(i=0;i<10;i++) poll(0);
   break;
  }
 }

 zapmenu();
 closedownt(CONF);

 return(conf_ok);
}


/***************************************************************************/
#define ReportError         0x000400DF

os_error * myreporterror(os_error* er, wimp_errflags flags)
{
 /* resetpointer();  */
 trans(er->errmess,sizeof(er->errmess));
 return os_swi3(os_X | ReportError, (int) er, flags, (int)"Hearsay");
}


os_error * myreporterrors(char * message, wimp_errflags flags)
{
 os_error e;
 e.errnum = 0;
 strcpy(&e.errmess[0], message);
 return(myreporterror(&e, flags));
}



void werr(int fatal, char* format, ...)
{
 va_list va;
 os_error e;
 e.errnum = 0;
 va_start(va, format);
 vsprintf(&e.errmess[0], format, va);
 va_end(va);
 myreporterror(&e, 0);
 if (fatal) exit(1);
}



void errorbox(char * message)
{
 myreporterrors(message,0);
}


/*
void messagebox(char * message)
{
 myreporterrors(message,1+16);
}
*/


void fatalerror(char * message)
{
 errorbox(message);
 exit(1);
}

void abend(os_error * e)
{
 /* if e is true, abend */
 if(e)
 {
  myreporterror(e,0);
  exit(1);
 }
}


void report(os_error * e)
{
 if(e)
 {
  myreporterror(e,0);
 }
}

/****************************************************************************/
/* Colour */



int getcolnumber(int pal)
{
 os_regset rx;
 rx.r[0]=pal;
 os_swix(ColourTrans_ReturnColourNumber,&rx);
 return(rx.r[0]);
}



int getgcolnumber(int pal)
{
 os_regset rx;
 rx.r[0]=pal;
 os_swix(ColourTrans_ReturnGCOL,&rx);
 return(rx.r[0]);
}



/*
static void setgcolour(int wcol,int eor)
{
 if(ncolours==63)
 {
  bbc_gcol(eor?3:0,wcol >> 2);
  bbc_tint(eor?2:0,wcol & 0x3);
 }
 else
 {
  bbc_gcol(eor?3:0,wcol);
 }
}
*/







static os_error * set_colour(int wcol,int mode)
{
 os_error       * err;
 os_regset        rx;
 int              temp;
 static int nosetcolour=0;

 err=NULL;

 if(!nosetcolour)
 {
  rx.r[0]=mode;
  rx.r[1]=wcol;

  err=os_swix(OS_SetColour,&rx); /* not in RISC OS 2 */
  if(err) nosetcolour=1;
 }

 if(nosetcolour)
 {
  if(ln2bpp==3)
  {
   temp=wcol & 0x78;
   wcol=wcol & 0x87;
   if(temp & 0x8) temp|=0x80;
   temp=temp>>1;
   temp&=0x78;
   wcol|=temp;

   err=bbc_gcol(mode,wcol>>2);
   bbc_tint(2,wcol & 0x3);
  }
  else
  {
   err=bbc_gcol(mode,wcol);
  }
 }

 return(err);
}








void seteorcol(int back,int front)
{
 int       wcol;

 wcol=wimpcolnos[back] ^ wimpcolnos[front];

 set_colour(wcol,0x3);


/*

 int wcol;
 wimp_palettestr palt;

 wimp_readpalette(&palt);

 wcol=palt.c[back].bytes.gcol ^ palt.c[front].bytes.gcol;

 setgcolour(wcol,1);

*/

}



/* in this version back is a real colour */

void seteorcolpal(int back,int front)
{
 int       wcol;

 wcol=wimpcolnos[front] ^ getcolnumber(back);

 set_colour(wcol,0x3);


/* int wcol;
 wimp_palettestr palt;

 wimp_readpalette(&palt);
 back=getgcolnumber(back);

 wcol=back ^ palt.c[front].bytes.gcol;

 setgcolour(wcol,1);
*/
}


int setgcol(int pal)
{
 os_regset rx;
 rx.r[0]=pal;
 rx.r[3]=0x100; /* dither */
 rx.r[4]=0x0;
 os_swix(ColourTrans_SetGCOL,&rx);
 return(rx.r[0]);
}


int setoppgcol(int pal)
{
 os_regset rx;
 rx.r[0]=pal & 0xFFFFFF00;
 rx.r[1]=0;
 rx.r[2]=0;
 rx.r[3]=0x0; /* 0x100; */ /* dither */
 rx.r[4]=0x0;
 os_swix(ColourTrans_SetOppGCOL,&rx);
 return(rx.r[0]);
}



os_error *selecttable(int sourcemode, int *sourcepal, int destmode,
                      int *destpal, char *transtab)
{
 os_regset regs ;

 regs.r[0] = sourcemode ;
 regs.r[1] = (int) sourcepal ;
 regs.r[2] = destmode ;
 regs.r[3] = (int) destpal ;
 regs.r[4] = (int) transtab ;

 return (os_swix(0x40740/*ColourTrans_SelectTable*/, &regs)) ;
}



/****************************************************************************/
                /* filing system bits and pieces */



int cstrcmp(char * first,char * second)
{
 int f;
 int s;

 while(1)
 {
  f=toupper(*first++);
  s=toupper(*second++);
  if(f!=s || !f) return(f-s);
 }
}




void setftype(char * filename,int type)
{
 char string[132]; 
 sprintf(string,"settype %s %X",filename,type);
 oscli(string);
}



char * leaf(char * filename)
{ char * p;

 p=strrchr(filename,'.');
 if(!p)
 {
  p=strrchr(filename,':');
  if(!p) p=filename;
  else   p+=1;
 } else  p+=1;
 return(p);
}




int filetype(load) int load;
{
 if((load & 0xFFF00000)==0xFFF00000)
           return((load >> 8) & 0xFFF);
 else return(CODE);
}




os_error * stat(char * name,fstat * f)
{
 os_error  *  errpoi;
 os_filestr  fiblock;

 fiblock.action=5;
 fiblock.name=name;
 errpoi=os_file(&fiblock);
 if(errpoi) return(errpoi);

 f->object=fiblock.action;
 f->length=fiblock.start;
 f->load=fiblock.loadaddr;
 f->exec=fiblock.execaddr;
 f->acc =fiblock.end;

 f->type=filetype(f->load);

 return(NULL);
}



os_error * stamp(char * name,fstat * f)
{
 os_filestr  fiblock;

 fiblock.action=1;
 fiblock.name=name;
 fiblock.loadaddr=f->load;
 fiblock.execaddr=f->exec;
 fiblock.start=0;
 fiblock.end=f->acc;
 return(os_file(&fiblock));
}


/*

int filelength(char * filename)
{
 fstat           f;
 os_error * errpoi;

 errpoi=stat(filename,&f);
 if(errpoi) return(0);

 return(f.length);
}
 
 */

/* returns 0 ==does not exist  1==file 2==dir */


int fexists(char * name)
{
 os_filestr  fiblock;

 fiblock.action=17;  /* don't use path */
 fiblock.name=name;
 os_file(&fiblock);

 return(fiblock.action);
}




os_error * createfile(char * name,int length,int type)
{
 os_filestr  fiblock;

 fiblock.action=0xB;
 fiblock.name=name;
 if(type==-1) type=0xFFD;
 fiblock.loadaddr=type;
 fiblock.start=0;
 fiblock.end=length;
 return(os_file(&fiblock));
}



char * kerror(void)
{
 _kernel_oserror * kerr;
 kerr=_kernel_last_oserror();
 if(kerr->errnum) return(kerr->errmess);
 else             return("");
}



static int  dirposn;

void startscan(void)
{
 dirposn=0;
}


/* PRM page 877 */
/* note that you can read nothing, but you have to continue */
/* search is only over when dirposn==-1                     */


int nextitem(char * dirname,fxstat * f,char * wild)
{
  char         buff[256];
  os_error   * errpoi;
  os_gbpbstr   gpblock;

  while(1)
  {
   if(dirposn==-1) return(0);

   gpblock.seq_point=dirposn;
   gpblock.action=10;
   gpblock.file_handle=(int)dirname;
   gpblock.data_addr=buff;
   gpblock.number=1;
   gpblock.buf_len=0x100;
   gpblock.wild_fld=wild;

   errpoi=os_gbpb(&gpblock);

   if(errpoi) return(0);

   dirposn=gpblock.seq_point;

   if(gpblock.number) break;
  }

  f->f.load  =(* (int *)(buff+0x0));
  f->f.exec  =(* (int *)(buff+0x4));
  f->f.length=(* (int *)(buff+0x8));
  f->f.acc   =(* (int *)(buff+0xC));
  f->f.object=(* (int *)(buff+0x10));
  strcpy(f->name,buff+0x14);
  f->f.type=filetype(f->f.load);

  return(1);
}


/*****************************************************************************/

int taskhandle;
int iconbaricon;

/* #define WORKSIZE 0x2900 */

#define WORKSIZE 0x3900

char workspace[WORKSIZE];        /* workspace for holding indirected icons */
char * worklo=workspace;
char * workhi=workspace+WORKSIZE;


/* #define WINDSIZE 0x8000 */

#define WINDSIZE 0x9000


int     whandle[MAXI];           /* wimp handle for internal handle */
wimp_wind * windpoi[MAXI];       /* pointer to window definition    */

char    windspc[WINDSIZE];       /* workspace for holding window definitions */
char *  windlo=windspc;
char *  windhi=windspc+WINDSIZE;

#define SPSIZE  0x1900
char    sprites[SPSIZE];         /* pointer to sprite space */


#define ReadSysInfo         (0x000400c0+50)

void starttask(void)
{
 os_regset r;

 taskhandle=wimpt_task();

 r.r[0]=0;
 os_swix(ReadSysInfo,&r);
 if(r.r[0]==1)
 {
  errorbox("Not within desktop environment");
  wimp_taskclose(taskhandle);
  exit(1);
 }
}




static char iconsp[16];

char * hsprites[3]={"!Hearsay1","!Hearsay2","!HearsayG"};

char   hearsayname[16];

static int hstate=2;


static void seticonbars(int recreate)
{
 wimp_icreate wic;

 wic.w=recreate?(-3):(-1);

 if(strlen(hearsayname))
 {
  wic.i.box.x0=0;
  wic.i.box.y0=-16;
  wic.i.box.x1=68;
  wic.i.box.y1=68+20;
  wic.i.flags=wimp_ITEXT   | wimp_IHCENTRE | wimp_ISPRITE |
              0x3000       | wimp_INDIRECT |
              (wimp_IFORECOL*7) | (wimp_IBACKCOL*1);

  wic.i.data.indirecttext.buffer=hearsayname;
  wic.i.data.indirecttext.bufflen=sizeof(hearsayname);
  wic.i.data.indirecttext.validstring=iconsp;

  sprintf(iconsp,"S%s",hsprites[hstate]);
 }
 else
 {
  wic.i.box.x0=0;
  wic.i.box.y0=0;
  wic.i.box.x1=68;
  wic.i.box.y1=68;
  wic.i.flags=wimp_ISPRITE | wimp_IHCENTRE | wimp_IVCENTRE | 
              0x3000       | wimp_INDIRECT;

  wic.i.data.indirectsprite.name=iconsp;
  wic.i.data.indirectsprite.spritearea=(void *)1;
  wic.i.data.indirectsprite.nameisname=12;

  strcpy(iconsp,hsprites[hstate]);
 }

 wimp_create_icon(&wic,&iconbaricon);
}



void seticonbar(void)
{
 seticonbars(0);
}



void sethearsayicon(int which)
{
 hstate=which;

 if(strlen(hearsayname)!=0) sprintf(iconsp,"S%s",hsprites[which]);
 else                       strcpy(iconsp,hsprites[which]);

 seti(-1,iconbaricon,0,0);
}


void sethearsayicontext(char * text)
{
 int oldicon;

 strcpy(hearsayname,text);

 oldicon=iconbaricon;
 seticonbars(1);
 wimp_delete_icon(-1,(wimp_i)oldicon);
}



void loadsprites(void)
{ 
 char string[256];

 sprintf(string,"%s.Sprites",path(HSYRD));

 sprite_area_initialise((sprite_area *)sprites,SPSIZE);
 abend(sprite_area_load((sprite_area *)sprites,string));
}



typedef struct {char * name;int tag;} windowname;


windowname windownames[MAXI]=
{
 "info",        INFO,
 "savefile",    SAVEFILE0,
 "conf",        CONF,
 "terminal",    VTERM,
 "vertical",    VTVERT,
 "settings",    STATUS,
 "replay",      REPLAY,
 "tek",         TEK,
 "Viewdata",    VDATA,
 "directory",   FILER,
 "transferbox", TRANBOX,
 "keypad",      KEYPAD,
 "btools",      BTOOLS,
 "CED",         CED,
 "sendframe",   SENDFRAME,
 "Setup",       TSETUP,
 "DialOptions", TDIALOPTIONS,
 "Printing",    PSTAT,
 "zoom",        ZOOM,
 "macros",      MACROS,
 "password",    PASSWORD,
 "ninfo",       NINFO,
 "selinfo",     SELINFO,
 "finfo",       FINFO,
 "Entry",       ENTRY,
 "Teledir",     TDIR,
 "VXPrint",     VXPRINT,
 "TEKPrint",    TEKPRINT,
 "Kermit",      KERMIT,
 "ascii",       ASCII,
 "characters",  VTSET,
 "commsfn",     COMMSFN,
 "CET",         TCET,
 "Xmodem",      TXMODEM,
 "Xmodem1K",    TXMODEM1K,
 "Ymodem",      TYMODEM,
 "Zmodem",      TZMODEM,
 "KeyboardVT",  TKEYVT,
 "KeyboardVX",  TKEYVX,
 "ConfigBatch", TBATCONFIG,
 "Choices",     TCHOICES,
 "LinkLevel",   TLINKLEVEL,
 "DisplayVT",   TDISPLAYVT,
 "DisplayVX",   TDISPLAYVX,
 "DisplayTEK",  TDISPLAYTEK,
 "LineMode",    TLINEMODE,
 "MiscVT",      TMISCVT,
 "MiscVX",      TMISCVX,
 "MiscTEK",     TMISCTEK
};




void loadtemp(int from,int n,char * sub)
{
 wimp_wind * ww;
 char nbuff[16];
 wimp_template wtmp;
 int to=from+n;
 int i;
 char filename[64];
 char * name;
 int    tag;

 sprintf(filename,"%s.%s",path(RESP),sub);
 abend(wimp_open_template(filename));

 for(i=from;i<to;i++)
 {
   name=windownames[i].name;
   tag=windownames[i].tag;

   strcpy(nbuff,name);
   ww=(wimp_wind *)windlo;

   wtmp.buf=ww;
   wtmp.work_free=worklo;
   wtmp.work_end=workhi;
   wtmp.font=0;
   wtmp.name=nbuff;
   wtmp.index=0;

   abend(wimp_load_template(&wtmp)); 
   worklo=wtmp.work_free;

   windpoi[tag]=ww;
   windlo=(char *)ww+sizeof(wimp_wind)+(ww->nicons)*sizeof(wimp_icon);

   if(windlo>windhi) fatalerror("No window space");
 }

/* dprintf(0,"windlo=%d windspc=%d  %d ",windlo,windspc,windlo-windspc);
 dprintf(1,"worklo=%d workspc=%d  %d ",worklo,workspace,worklo-workspace); */

 wimp_close_template();
}




void loadtemps(void)
{ 
 int i;
 for(i=0;i<MAXI;i++) whandle[i]=0;
 loadtemp(0,49,"<Hearsay$Templates>");
}




void writetitle(int tag,char * title)
{
 wimp_wind  * wp;

 wp=windpoi[tag];

 if(wp->titleflags && wimp_INDIRECT)
 {
  xstrncpy(wp->title.indirecttext.buffer,title,
           wp->title.indirecttext.bufflen);
 }
}




int createwindowsub(int tag,char * title)   /* called with tag for argument */
{
 int          wh;
 wimp_wind  * wp;
 os_error   * ep;

 if(whandle[tag]) return(whandle[tag]);

 wp=windpoi[tag];

 if(tag==REPLAY || tag==KEYPAD)
  wp->spritearea=sprites;
 else
  wp->spritearea=(char *)1; /* use common sprites for these */


 if(title)
 {
  if(wp->titleflags & wimp_INDIRECT)
    strcpy(wp->title.indirecttext.buffer,title);
  else
  {
   if(strlen(title)>=12) memcpy(wp->title.text,title,12);
   else                  strcpy(wp->title.text,title);
  }
 }

 ep=wimp_create_wind(wp,&wh);
 if(ep)
 {
  report(ep);
  wh=0;
 }

 whandle[tag]=wh;

 return(wh);
}


int createwindow(int tag) 
{
 return(createwindowsub(tag,NULL));
}

void closedownt(int tag)
{
 if(whandle[tag])
 {
  wimp_close_wind(whandle[tag]);
  wimp_delete_wind(whandle[tag]);
  whandle[tag]=0;
 }
}

void closedown(int window)
{
 int i;

 for(i=0;i<MAXI;i++)
 {
  if(whandle[i]==window)
  {
   closedownt(i);
   return;
  }
 }

 wimp_close_wind(window);
}

/****************************************************************************/

// #define PROD 

#ifndef DEMO 

#ifndef PROD

void dprintf(int line,char * format, ...)
{
 va_list args;
 char v[128];
 va_start(args, format);
 vsprintf(v, format, args);
 bbc_vdu(4);bbc_vdu(30);
 while(line--) bbc_vdu(10);
 printf("%-40s",v);
 bbc_vdu(5);
 if(isshift) bbc_get();
 va_end(args);
}

#else

void dprintf(int line,char * format, ...)
{
 va_list args;
 char v[128];
 va_start(args, format);
 vsprintf(v, format, args);

 va_end(args);
}

#endif

#else

void dprintf(int line,char * format, ...)
{
 va_list args;
 char v[128];
 va_start(args, format);
 vsprintf(v, format, args);

 va_end(args);
}

#endif



/*****************************************************************************/


int iconinredraw(wimp_redrawstr * redrawstr)
{
 int        ox;
 int        oy;
 int        ylo;
 int        yhi;
 int        xlo;
 int        xhi;

 ox=redrawstr->box.x0-redrawstr->scx;
 oy=redrawstr->box.y1-redrawstr->scy;

 ylo=(redrawstr->g.y1-oy);            /* small -ve. number, top of window */
 yhi=(redrawstr->g.y0-oy);            /* bigger, bottom of window */
 xlo=(redrawstr->g.x0-ox);
 xhi=(redrawstr->g.x1-ox);

 return(((ix0>=xlo && ix0<=xhi) ||
         (ix1>=xlo && ix1<=xhi) ||
         (xlo>=ix0 && xlo<=ix1) ||
         (xhi>=ix0 && xhi<=ix1)) &&
        ((iy0<=ylo && iy0>=yhi) ||
         (iy1<=ylo && iy1>=yhi) ||
         (ylo>=iy0 && ylo<=iy1) ||
         (yhi>=iy0 && yhi<=iy1)));
}


/****************************************************************************/

#ifdef NEVER

int wimpfonthandle;
int wimpfontlead;
int wimpfontheight;
int wimpfontwidth;
int wimpavfontwidth;


#define FONTCODE 26


void wimpfontstart(void)
{
 os_regset rx;
 char    * p;
 char      fontname[256];
 int       xsize=192;
 int       ysize=192;
 int       temp;
 font_info fi;
 int       i;
 int       j;

 wimpfonthandle=0;

 if((p=getenv("Wimp$Font"))!=NULL)
 {
  strcpy(fontname,p);

  if((p=getenv("Wimp$FontSize"))!=NULL) 
  {
   if(sscanf(p,"%d",&temp)==1) ysize=temp;
  }

  if((p=getenv("Wimp$FontWidth"))!=NULL)
  {
   if(sscanf(p,"%d",&temp)==1) xsize=temp;
  }

  font_find(fontname,xsize,ysize,0,0,&wimpfonthandle);
 }

 if(wimpfonthandle)
 {
  rx.r[0]=wimpfonthandle;
  os_swix(Font_ReadInfo,&rx);
  wimpfontlead=rx.r[4];
  wimpfontheight=rx.r[4]-rx.r[2];
  wimpfontwidth=rx.r[3]-rx.r[1];


  fontname[0]=FONTCODE;
  fontname[1]=wimpfonthandle;

  j=2;

  for(i=32;i<127;i++)
  {
   fontname[j]=i;
   j++;
  }

  for(i=160;i<256;i++)
  {
   fontname[j]=i;
   j++;
  }

  fontname[j]=0;

  font_stringbbox(fontname,&fi);

  wimpavfontwidth=(fi.maxx-fi.minx)/((j-2)*400);
 }
 else
 {
  wimpfontheight=32;
  wimpfontwidth=wimpavfontwidth=16;
  wimpfontlead=0;
 }
}

void wimpfontend(void)
{
 if(wimpfonthandle)
 {
  font_lose(wimpfonthandle);
  wimpfonthandle=0;
 }
}


#define ColourTrans_SetFontColours     0x04074f

void stringat(int x,int y,char * string,int col,int height)
{
 os_regset rx;
 int       shift;

 if(wimpfonthandle)
 {
  shift=(height-deltay-wimpfontheight)/2+wimpfontlead;

  rx.r[0]=wimpfonthandle; 
  rx.r[1]=vdupal.c[(col>>8) & 0xFF].word;
  rx.r[2]=vdupal.c[col & 0xFF].word;
  rx.r[3]=14;

  os_swix(ColourTrans_SetFontColours,&rx);

  font_paint(string,font_ABS|font_OSCOORDS,x,y-shift);
 }
 else
 {
  wimp_setcolour(col & 0xFF);
  shift=(height+deltay-32)/2;
  bbc_move(x,y-shift);
  bbc_stringprint(string);
 }
}

#endif




#define FONTCODE 26



int wimpavfontwidth=16;


int wimpfonthandle;
int wimpfontlead;
int wimpfontheight;
int wimpfontwidth;




void wimpfontstart(void)
{
 os_regset rx;
 char    * p;
 char      fontname[256];
 int       xsize=192;
 int       ysize=192;
 int       temp;
 font_info fi;
 int       i;
 int       j;

 wimpfonthandle=0;

 wimpfontheight=32;
 wimpfontwidth=wimpavfontwidth=16;
 wimpfontlead=0;


 if(wimp_version>=350) 
 {
  j=2;
  for(i=32;i<127;i++)
  {
   fontname[j]=i;
   j++;
  }
  for(i=160;i<256;i++)
  {
   fontname[j]=i;
   j++;
  }
  fontname[j]=0;


  rx.r[0]=1+(1<<30);
  rx.r[1]=(int)(fontname+2);
  rx.r[2]=j;


  if(!os_swix(Wimp_TextOp,&rx))
  {
   wimpavfontwidth=rx.r[0]/j;
  }
 }
 else
 {
  if((p=getenv("Wimp$Font"))!=NULL)
  {
   strcpy(fontname,p);
 
   if((p=getenv("Wimp$FontSize"))!=NULL) 
   {
    if(sscanf(p,"%d",&temp)==1) ysize=temp;
   }

   if((p=getenv("Wimp$FontWidth"))!=NULL)
   {
    if(sscanf(p,"%d",&temp)==1) xsize=temp;
   }

   font_find(fontname,xsize,ysize,0,0,&wimpfonthandle);
  }

  if(wimpfonthandle)
  {
   j=2;
   for(i=32;i<127;i++)
   {
    fontname[j]=i;
    j++;
   }
   for(i=160;i<256;i++)
   {
    fontname[j]=i;
    j++;
   }
   fontname[j]=0;


   rx.r[0]=wimpfonthandle;
   os_swix(Font_ReadInfo,&rx);
   wimpfontlead=rx.r[4];
   wimpfontheight=rx.r[4]-rx.r[2];
   wimpfontwidth=rx.r[3]-rx.r[1];


   fontname[0]=FONTCODE;
   fontname[1]=wimpfonthandle;

   font_stringbbox(fontname,&fi);

   wimpavfontwidth=(fi.maxx-fi.minx)/((j-2)*400);
  }
 }
}



void wimpfontend(void)
{
 if(wimpfonthandle)
 {
  font_lose(wimpfonthandle);
  wimpfonthandle=0;
 }
}





void stringat(int x,int y,char * string,int col,int height)
{
 os_regset rx;
 int       shift;


 if(wimpfonthandle)
 {
  shift=(height-deltay-wimpfontheight)/2+wimpfontlead;

  rx.r[0]=wimpfonthandle; 
  rx.r[1]=vdupal.c[(col>>8) & 0xFF].word;
  rx.r[2]=vdupal.c[col & 0xFF].word;
  rx.r[3]=14;

  os_swix(ColourTrans_SetFontColours,&rx);

  font_paint(string,font_ABS|font_OSCOORDS,x,y-shift);
 }
 else
 {
  y-=(height+deltay-32)/2;
 
  wimp_setcolour(col & 0xFF);
  wimp_setcolour(((col>>8) & 0xFF)|128);

  rx.r[0]=2+(1<<30);
  rx.r[1]=(int)string;
  rx.r[2]=-1;
  rx.r[3]=-1;
  rx.r[4]=x;
  rx.r[5]=y-32+8; /*2*deltay; */

  if(wimp_version<350 || os_swix(Wimp_TextOp,&rx))
  {
   bbc_move(x,y);
   bbc_stringprint(string);
  }
 }
}







void plinthtext(int x,int y,int w,int h,char * string,int col)
{
 int i;

 wimp_setcolour((col>>8) & 0xFF);
 bbc_rectanglefill(x,y,w,-h);

 wimp_setcolour(4);

 for(i=0;i<4;i+=deltay)
 {
  bbc_move(x,y+i);
  bbc_draw(x+w,y+i);
 }

 for(i=0;i<4;i+=deltax)
 {
  bbc_move(x+i,y);
  bbc_draw(x+i,y-h);
 }

 wimp_setcolour(0);

 for(i=0;i<4;i+=deltay)
 {
  bbc_move(x,y-h+i);
  bbc_draw(x+w,y-h+i);
 }

 for(i=0;i<4;i+=deltax)
 {
  bbc_move(x+w-i,y);
  bbc_draw(x+w-i,y-h);
 }

 stringat(x+6,y,string,col,h);
}


void noplinthtext(int x,int y,int w,int h,char * string,int col)
{
 wimp_setcolour((col>>8) & 0xFF);
 bbc_rectanglefill(x,y,w,-h);
 wimp_setcolour(7);
 bbc_rectangle(x,y,w,-h);
 stringat(x+8,y,string,col,h);
}


